Skip to content

Publishing NuGet Packages with Default Files Using Visual Studio

TLDR

  • When developing NuGet packages, it is recommended to prioritize .NET Standard as the target platform.
  • Modern .NET projects allow you to configure package information directly in the .csproj file, eliminating the need for a separate .nuspec file.
  • To automatically copy configuration files during package installation, the package.config mode requires an install.ps1 script, while the PackageReference mode relies on <Content> settings within the project file.
  • For .NET Framework projects using PackageReference, file copying or install.ps1 execution may not trigger correctly; compatibility testing is recommended for this scenario.

Fundamentals Before Developing a Package

Choosing a Target Platform

When developing a NuGet package, it is recommended to choose .NET Standard to ensure cross-platform support. If you need to support older .NET Framework versions, you can configure TargetFrameworks in your project file for multi-targeting:

xml
<PropertyGroup>
  <TargetFrameworks>netstandard2.1;netstandard2.0;net45</TargetFrameworks>
</PropertyGroup>

Editing Package Information

Modern Visual Studio allows you to define NuGet package metadata directly in the .csproj file, replacing the traditional .nuspec file. Key settings include:

  • Version: It is recommended to follow SemVer specifications.
  • PackageLicenseExpression: If using common licenses like MIT or BSD, please use SPDX license identifiers.
  • PackageId: The package name; if not specified, it defaults to the project name.

Publishing NuGet Packages with Files

When including default configuration files (such as Config.json) in a package, you must consider the two primary installation formats: package.config and PackageReference.

File Configuration

To include files in a package and handle them during installation, configure your .csproj as follows:

xml
<ItemGroup>
  <Content Include=".\Config.json">
    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    <PackageCopyToOutput>true</PackageCopyToOutput>
  </Content>
  <None Include=".\install.ps1">
    <Pack>True</Pack>
    <PackagePath>tools</PackagePath>
  </None>
</ItemGroup>

Purpose of install.ps1

When does this issue arise? When you use the package.config format to install a package and wish to automatically set file properties (such as Build Action or Copy to Output Directory).

This script is only effective for package.config. An example is provided below:

shell
param($installPath, $toolsPath, $package, $project)

# Set file name
$configItem = $project.ProjectItems.Item("Config.json")

# Set 'Copy To Output Directory' to PreserveNewest (2)
$copyToOutput = $configItem.Properties.Item("CopyToOutputDirectory")
$copyToOutput.Value = 2

# Set 'Build Action' to Content (2)
$buildAction = $configItem.Properties.Item("BuildAction")
$buildAction.Value = 2

Validation Results for Different Installation Scenarios

1. .NET Framework with package.config

  • Result: Success. install.ps1 executes automatically, and file properties are correctly set to "Content" and "Copy if newer".

2. ASP.NET Core (using PackageReference)

  • Result: Partially successful. install.ps1 does not execute, but the file is added to the project, and copy properties generally function as expected.

3. .NET Framework with PackageReference

  • Result: Failure. This combination does not execute install.ps1, and files are typically not automatically copied to the target project.
  • Recommendation: If your package must support this scenario, it is recommended to advise users in the documentation to add the configuration file manually, or consider providing initialization code instead of relying on automatic copying.

WARNING

NuGet.org only accepts license expressions approved by the Open Source Initiative or the Free Software Foundation.


Change Log

  • 2022-11-08 Initial documentation created.